/**
 * @description: 钉钉授权登录及用户信息获取 service
 * @version: 0.0.1
 * @author: z..
 * @Date: 2023-06-12 18:16:39
 */

import { Provide, Inject, HttpClient } from '@midwayjs/core';
import { Context } from '@midwayjs/koa';
import { RobotWebapiRecordsModel } from "../entity/robot_webapi_records.method";
import { RobotWebapiLogsModel } from "../entity/robot_webapi_logs.method";

import { SendDingtalkMsgService } from "./send.dingtalk.msg.service";

const axios = require('axios');
const moment = require('moment');
const qs = require("querystring")

@Provide()
export class ScheduleTasksWebapiService {
  @Inject()
  ctx: Context;

  @Inject()
  RobotWebapiRecordsModel: RobotWebapiRecordsModel;

  @Inject()
  RobotWebapiLogsModel: RobotWebapiLogsModel;

  @Inject()
  SendDingtalkMsgService: SendDingtalkMsgService;

  /**
     * 手动测试  webapi
     * @param {*} taskObj 
     * @returns 
     */
  async webApiManualTesting(taskObj: any): Promise<any> {
    const _nday = moment().format('YYYY-MM-DD');
    //  计算现在距离结束日期天数计算
    const daysNum = moment(taskObj.webapi_endtime).diff(moment(_nday), 'days');
    const userIds = taskObj.webapi_userid ? taskObj.webapi_userid.split(",") : [];
    //  http请求校验
    let res = await this.sendApiRequest(taskObj);
    //  钉钉消息发送
    const _msgRes = await this.SendDingtalkMsgService.dingtalkMsg({
      id: taskObj.id,
      alarm_config: taskObj.webapi_config,
      alarm_name: taskObj.webapi_name,
      alarm_content: taskObj.webapi_content || "",
      alarm_type: taskObj.webapi_type,
      user_ids: userIds,
      msg: "手动测试",
      days_num: daysNum,
      isApi: true,
      apiRes: {
        logRes: res.logRes,
        isSuccess: res.isSuccess
      },
      end_time: taskObj.webapi_endtime
    });

    //  钉钉通知是否成功
    let _ddSuccess = _msgRes && _msgRes.success ? true : false;

    //  更新测试结果
    await this.RobotWebapiRecordsModel.getTestingById({
      id: taskObj.id,
      testingStatus: res.isSuccess ? _ddSuccess ? 1 : 2 : 0,
      testingTime: moment().format('YYYY-MM-DD HH:mm:ss')
    });

    //  机器人配置
    res.alarmRes = JSON.stringify(_msgRes);
    //  请求日志存储
    await this.RobotWebapiLogsModel.insertWebapiLog({ ...res, isTesting: 1 });
    return {
      httpRes: res,
      alarmRes: _msgRes
    }
  }

  /**
   * 定时任务执行 查询正在运行中的webapi信息
   * 接口成功消息 晚9点至早9点不通知
   */
  async webApiQueueTasks(): Promise<any> {
    const _queryLists = await this.RobotWebapiRecordsModel.getDataByStatus("START");

    // if (!_queryLists || !_queryLists.length) throw new httpError.BadRequestError("暂无正在进行中的任务");
    if (!_queryLists || !_queryLists.length) return [];

    //  根据日期筛选过滤
    const _filterArr = await this.filterByDate(_queryLists);

    // if (!_filterArr || !_filterArr.length) throw new httpError.BadRequestError("暂无需要处理的数据");
    if (!_filterArr || !_filterArr.length) return [];

    //  判断当前是否是工作时间段
    const _timeStatus = await this.checkAuditTime('09:00', '21:00');

    //  发送接口调用请求
    let _returnArr = [];
    for (let i = 0; i < _filterArr.length; i++) {
      const el = _filterArr[i];
      let _apiRes = await this.sendApiRequest(el.item);
      let _msgRes = null;
      let _send_msg = el.item.send_success_msg ? true : false;
      //  当前需要推送消息 但是处于休息时间  不推送消息
      if (_send_msg && !_timeStatus) {
        _send_msg = false;
      }

      // 接口调用失败 无论任何时间段范围,必须推送消息
      if (!_apiRes.isSuccess) {
        _send_msg = true;
      }

      let _ddSuccess = true;
      if (_send_msg) {
        //  钉钉消息发送
        _msgRes = await this.SendDingtalkMsgService.dingtalkMsg({
          id: el.item.id,
          alarm_config: el.item.webapi_config,
          alarm_name: el.item.webapi_name,
          alarm_content: el.item.webapi_content || "",
          alarm_type: el.item.webapi_type,
          user_ids: el.userIds,
          days_num: el.daysNum,
          isApi: true,
          apiRes: {
            logRes: _apiRes.logRes,
            isSuccess: _apiRes.isSuccess
          },
          end_time: el.item.webapi_endtime
        });
        //  钉钉通知是否成功
        _ddSuccess = _msgRes && _msgRes.success ? true : false;
      }

      //  更新测试结果
      await this.RobotWebapiRecordsModel.getTestingById({
        id: el.item.id,
        testingStatus: _apiRes.isSuccess ? _ddSuccess ? 1 : 2 : 0,
        testingTime: moment().format('YYYY-MM-DD HH:mm:ss')
      })

      //  机器人配置
      _apiRes.alarmRes = _msgRes ? JSON.stringify(_msgRes) : "";
      //  请求日志存储
      await this.RobotWebapiLogsModel.insertWebapiLog({ ..._apiRes, isTesting: 1 });
      _returnArr.push(_apiRes);
    }
    return _returnArr;
  }


  /**
   * 根据日期筛选过滤数据
   * @param {*} dataArr 
   * @returns 
   */
  async filterByDate(dataArr: any): Promise<any> {
    try {
      const _nday = moment().format('YYYY-MM-DD');
      let resArr = [];
      for (let i = 0; i < dataArr.length; i++) {
        const item = dataArr[i];
        //  计算现在距离结束日期天数计算
        const daysNum = moment(item.webapi_endtime).diff(moment(_nday), 'days');

        if (daysNum >= 0) {
          const userIds = item.webapi_userid ? item.webapi_userid.split(",") : [];
          //  当前时间
          const _nowTime = new Date().getTime();
          //  上次运行时间
          const _lastTime = new Date(item.testing_time).getTime();
          // 检测间隔时间
          const _intervalNum = Number(item.testing_interval) * 1000 * 60 * 60;
          if ((_lastTime + _intervalNum) <= _nowTime) {
            resArr.push({ item, userIds, daysNum });
          }
        } else {
          //  任务时间一过，修改任务状态为已完成
          await this.RobotWebapiRecordsModel.updateWebapiStatus({
            id: item.id, webapiStatus: "END"
          });
        }
      }
      return resArr;
    } catch (error) {
      return [];
    }
  }

  /**
   * 发送api接口请求
   * @param {*} item 
   */
  async sendApiRequest(item: any): Promise<any> {
    try {
      const url = item.webapi_domain + item.webapi_path;
      const { success, httpRes } = await this.axiosRequest(item.webapi_method, url, JSON.parse(item.webapi_data), item.webapi_class);
      let _obj = {
        webapiId: item.id,
        logName: `${item.webapi_name}-监测日志`,
        alarmRes: ""
      }

      if (success) {
        //  网页检测 直接判断http 200响应
        if (item.webapi_class == "web") {
          _obj['logRes'] = (httpRes.status === 200) ? "https请求状态200，请求成功" : Buffer.isBuffer(httpRes.data) ? "https请求data数据为buffer，请求成功" : `https请求状态${httpRes.status}，请求失败`;
          _obj['isSuccess'] = (httpRes.status === 200) ? true : Buffer.isBuffer(httpRes.data) ? true : false;
          // _obj['logRes'] = (httpRes.status === 200) ? "https请求状态200，请求成功" : `https请求状态${httpRes.status}，请求失败`;
          // _obj['isSuccess'] = (httpRes.status === 200) ? true : false;
          return _obj;
        }

        if (item.webapi_check) {
          //  需要校验返回结果
          const _checkArr = item.webapi_check.split(":");
          if (_checkArr && _checkArr.length == 2) {
            const _str = String(httpRes.data[_checkArr[0]]).toUpperCase();
            const _str2 = String(_checkArr[1]).toUpperCase();
            _obj['logRes'] = JSON.stringify(httpRes.data);
            _obj['isSuccess'] = (_str === _str2) ? true : false;
            return _obj;
          }else if(_checkArr.length == 1){
            _obj['logRes'] = JSON.stringify(httpRes.data);
            _obj['isSuccess'] = (item.webapi_check === httpRes.data) ? true : false;
            return _obj;
          }
        }
        //  返回结果不需要校验，直接判定http 状态为200即可
        _obj['logRes'] = httpRes.data ? JSON.stringify(httpRes.data) : JSON.stringify(httpRes);
        _obj['isSuccess'] = (httpRes.status === 200) ? true : false;
      } else {
        //  返回结果不需要校验，直接判定http 状态为200即可
        _obj['logRes'] = JSON.stringify(httpRes);
        _obj['isSuccess'] = false;
      }
      return _obj;
    } catch (error) {
      return { isSuccess: false, logRes: error }
    }
  }


  /**
   * 发起请求
   * @param {*} method 
   * @param {*} url 
   * @param {*} body 
   * @param {*} headers
   * @param {*} type  检测类型, web/api
   * @returns 
   */
  async httpRequest(method: string, url: string, data: any, type: any): Promise<any> {
    try {
      const _url = (typeof (data.params) == 'object' && JSON.stringify(data.params) != '{}') ? `${url}?${qs.stringify(data.params)}` : url;
      const _method = method.toUpperCase();
      const httpclient = new HttpClient();
      const res = await httpclient.request(_url, {
        method: _method,
        data: data.body || {},
        dataType: (type == "api") ? data.dataType || 'json' : '',
        contentType: (type == "api") ? data.dataType || 'json' : 'json',   // 发送的 post 为 json
        headers: data.headers || {}
      });
      return { success: true, httpRes: res };
    } catch (error) {
      return { success: false, msg: "scheduleTasksWebapi-httpRequest-系统错误", httpRes: error };
    }
  }

    /**
   * 发起请求
   * @param {*} method 
   * @param {*} url 
   * @param {*} body 
   * @param {*} headers
   * @param {*} type  检测类型, web/api
   * @returns 
   */
    async axiosRequest(method: string, url: string, data: any, type: any): Promise<any> {
      try {
        const _url = (typeof (data.params) == 'object' && JSON.stringify(data.params) != '{}') ? `${url}?${qs.stringify(data.params)}` : url;
        const _method = method.toUpperCase();
        const res = await axios({
          method: _method,
          url: _url,
          data: data.body || {}
        });
        return { success: true, httpRes: res };
      } catch (error) {
        return { success: false, msg: "scheduleTasksWebapi-axiosRequest-系统错误", httpRes: error };
      }
    }


  /**
   * 校验是否是指定时间段范围
   * @param {*} startTime 
   * @param {*} endTime 
   * @returns 
   */
  async checkAuditTime(startTime: any, endTime: any): Promise<any> {
    // 获取当前时间
    const date = new Date();
    // 获取当前时间的年月日
    const dataStr = `${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()} `;

    // 获取开始时间、结束时间、现在时间的时间戳
    let startDate = new Date(dataStr + startTime).getTime();
    let endDate = new Date(dataStr + endTime).getTime();
    let nowDate = date.getTime();

    const s = startDate > endDate; // 判断开始时间否大于结束时间

    if (s) [startDate, endDate] = [endDate, startDate]; // 若开始时间否大于结束时间则交换值

    // 判断现在的时间是否在开始时间和结束时间之间，若s为true则结果取反
    if (nowDate > startDate && nowDate < endDate) {
      return s ? false : true;
    } else {
      return s ? true : false;
    }
  }
}